#include "svgnodecontainer.h"
#include "svgnodeelementfactory.h"
#include "graphprimitiveprop.h"
#include "colortransformer.h"
#include <QStyleOptionGraphicsItem>"
#include "ilink.h"

SvgNodeContainer::SvgNodeContainer(SvgNode *parent)
        :SvgNode(parent)
{
}


void SvgNodeContainer::paint(QPainter *painter,
	const QStyleOptionGraphicsItem *option,
	QWidget *widget){


	if (0)
		foreach(SvgNode* element, m_childern) {
		element->paint(painter, option, widget);

	}
	
	updateFrame();
	updateShape();
	/*QPen pen = painter->pen();
	pen.setStyle(Qt::DashLine);
	painter->setPen(pen);
	painter->drawRect(m_frame);*/
	
	

}

void SvgNodeContainer::fromXmlImpl(const QDomElement &xml) {
    QDomNodeList subs = xml.childNodes();

    for (int i= 0 ; i < subs.count() ;i++){

         QDomNode xmlNode = subs.item(i);

		 if (xmlNode.nodeName() == "props")
		 {
			 //read prop
			 for (int j = 0; j < xmlNode.childNodes().count(); j++){
				 QDomElement prop = xmlNode.childNodes().item(j).toElement();
				 QString  name = prop.attribute("name");
				 GraphPrimitiveProp::PropType type = (GraphPrimitiveProp::PropType)prop.attribute("type").toInt();
				 QString tmpDefault = prop.attribute("defaultValue");
				 QString tmpCurrent = prop.attribute("value");
				 QVariant defaultValue;
				 switch (type)
				 {
				 case GraphPrimitiveProp::FLOAT:
					 defaultValue = prop.attribute("defaultValue").toDouble();
					 if (prop.hasAttribute("value"))
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue, prop.attribute("value").toDouble()));
					 else
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue));
					 break;
				 case GraphPrimitiveProp::INT:
					 defaultValue = prop.attribute("defaultValue").toInt();
					 if (prop.hasAttribute("value"))
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue, prop.attribute("value").toInt()));
					 else
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue));
					 break;
				 case GraphPrimitiveProp::STRING:
					 defaultValue = prop.attribute("defaultValue");
					 if (prop.hasAttribute("value"))
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue, prop.attribute("value")));
					 else
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue));
					 break;
				 case GraphPrimitiveProp::DEVICETYPE:
					 defaultValue = prop.attribute("defaultValue").toInt();
					 if (prop.hasAttribute("value"))
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue, prop.attribute("value").toInt()));
					 else
						 this->m_props.append(GraphPrimitiveProp(name, type, defaultValue));
					 break;
				 default:
					 break;
				 }
			 }
		 }
		 else{
			 SvgNode *node = SvgNodeElementFactory::createNode(xmlNode.toElement());
			 if (!node)
				 continue;
			 node->fromXml(xmlNode.toElement());
			 this->add(node);
		 }
        
    }

	updateFrame();
	updateShape();
}

void SvgNodeContainer::toXml(QDomElement &parent) const{
	SvgNode::toXml(parent);
}

QDomElement SvgNodeContainer::toXmlImpl(QDomElement &parent) const{
	QDomElement curr = parent.ownerDocument().createElement("g");
	//write prop
	if (!this->m_props.empty())
	{
		QDomElement props = parent.ownerDocument().createElement("props");

        foreach (const GraphPrimitiveProp & p , this->m_props)
		{
			QDomElement prop = parent.ownerDocument().createElement("prop");
			prop.setAttribute("name", p.name());
			prop.setAttribute("type", p.type());
			prop.setAttribute("defaultValue", p.defaultValue().toString());
			prop.setAttribute("value", p.value().toString());
			props.appendChild(prop);
		}
		curr.appendChild(props);
	}
	foreach(SvgNode* element, m_childern) {
		element->toXml(curr);
	}


	return curr;
}

void SvgNodeContainer::toXmlComplete(QDomElement &current) const{
	QString transformStr;
	QPointF pTopLeft = m_frame.topLeft() + QPointF(m_strokeWidth / 2.f, m_strokeWidth / 2.f);
	QPointF offset = fixedOriginPoint();
	QPointF pos = this->pos();
	transformStr.append(QString(" translate(%1 %2) ").arg(this->pos().x() + offset.x() - pTopLeft.x()).arg(this->pos().y() + offset.y() - pTopLeft.y()));
	if (this->m_rotationAngle)
	{
		QPointF center = pTopLeft + QPointF((m_frame.width() - m_strokeWidth) / 2.f, (m_frame.height() - m_strokeWidth) / 2.f);
		transformStr.append(QString(" rotate(%1 %2 %3) ").arg(this->m_rotationAngle).arg(center.x()).arg(center.y()));
	}
	current.setAttribute("transform", transformStr);
}


void SvgNodeContainer::createRelations(SvgNode *top){
	foreach(SvgNode* element, m_childern) {
		element->createRelations(top);
	}

}

void  SvgNodeContainer::add(SvgNode* obj){
	SvgNode::add(obj);
	QTransform t = this->transform();
	this->resetTransform();
	updateFrame();
	updateShape();
	this->setTransform(t);
}

void  SvgNodeContainer::remove(SvgNode *obj){
	SvgNode::remove(obj);
	updateFrame();
	updateShape();
}

void  SvgNodeContainer::setParentNode(SvgNode *parent){
	SvgNode::setParentNode(parent);
	updateFrame();
	updateShape();
}


void SvgNodeContainer::updateFrame(){


	/*//reset frame	
	qreal minx = 999999;
	qreal miny = 999999;
	qreal maxx = -999999;
	qreal maxy = -999999;
	this->boundaryRangeInScene(minx, miny, maxx, maxy);
	const int pad = 0;
	QRectF rect = QRectF(minx - m_strokeWidth / 2.f - pad, miny - m_strokeWidth / 2.f - pad, (maxx - minx) + m_strokeWidth + pad * 2, (maxy - miny) + m_strokeWidth + pad*2);
	m_frame = this->mapRectFromScene(rect);*/

	qreal left, top, right, bottom;
	left = top = 1.e10;
	right = bottom = -1.e10;
	foreach(SvgNode *node, m_childern){
		QRectF frame = this->mapRectWithNoTransform(node);

		if (left > frame.x())
			left = frame.x();
		if (top > frame.y())
			top = frame.y();
		if (right < frame.x() + frame.width())
			right = frame.x() + frame.width();
		if (bottom < frame.y() + frame.height())
			bottom = frame.y() + frame.height();
	}
	m_frame = QRectF(left, top, right - left, bottom - top);
	
}

QList<QPointF> SvgNodeContainer::alignPoints(QPointF &center){

	return QList<QPointF>();
}
void SvgNodeContainer::boundaryRangeInScene(qreal &left, qreal &top, qreal &right, qreal &bottom) const{
	if (m_childern.isEmpty()){
		left = top = right = bottom = 0;
		return;
	}
	qreal l, t, r, b;
	m_childern.first()->boundaryRangeInScene(left, top, right, bottom);
	for (int i = 1; i < m_childern.count();i++){
		SvgNode *node = m_childern[i];
		node->boundaryRangeInScene(l, t, r, b);
		if (left > l)
			left = l;
		if (top > t)
			top = t;
		if (right < r)
			right = r;
		if (bottom < b)
			bottom = b;
	}
}

QRectF SvgNodeContainer::mapRectWithNoTransform(SvgNode *from){
	QList<QTransform> tmpTranList;
	tmpTranList.append(from->transform());
	from->resetTransform();
	SvgNode *tmp = from;
	while ((tmp = tmp->parentNode()) && tmp->svgType() == SvgNode::SVG_GROUP)
	{
		tmpTranList.append(tmp->transform());
		tmp->resetTransform();
	}

	QRectF frame = from->mapRectToScene(from->frame());
	frame = this->mapRectFromScene(frame);

	from->setTransform(tmpTranList.first());
	tmpTranList.pop_front();
	tmp = from;
	while ((tmp = tmp->parentNode()) && tmp->svgType() == SvgNode::SVG_GROUP)
	{
		tmp->setTransform(tmpTranList.first());
		tmpTranList.pop_front();
	}

	return frame;
}